﻿/*************************************************************************************
 * 工    具：  HK_SlidePage3D
 * 
 * 描    述：  3D轮播图工具，支持自适应屏幕布局与深度视觉差。功能包含：
 *             自动旋转与手动控制切换
 *             子物体深度排序与层级管理
 *             透视缩放及透明度渐变效果
 *             平滑旋转动画（基于DOTween）
 * 
 * 版    本：  V1.3
 * 作    者：  京产肠饭
 * 
 * 创    建：  2025/04/03  V1.0
 *
 * 更    新：  2025/04/25  V1.1
 *            1.功能新增：新增两个public方法，供外界调用，可通过代码进行“上一页”和“下一页”的切换，与HK_SlidePage2D功能一致
 *
 *			  2025/05/03  V1.2
 *            1.Bug修复：Content下子元素透明度及缩放的计算方式，使用localPosition.z进行深度计算，避免父物体移动时深度计算错误的问题
 *            2.性能优化：缓存子元素的 CanvasGroup组件，避免重复查找，提高性能
 *
 *			  2025/05/03  V1.3
 *            1.功能优化：切页的时候，使用渐变处理各页面透明度变化
 * 
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using System.Collections.Generic;
using DG.Tweening;
using HKTools;
using UnityEngine;

[ExecuteAlways]
public class HK_SlidePage3D : MonoBehaviour
{
	[Header("内容容器"), SerializeField] Transform content;
	[Header("旋转基准点"), SerializeField] Transform rotationPivot;
	[SerializeField] float radiusMult = 100f;   // 半径乘数，用于动态计算布局半径
	[Header("最小缩放比例"), SerializeField, Range(0f, 1f)] float minScale = 0.5f;
	[Header("透明度递减强度"), SerializeField, Range(3, 20)] int alphaExponent = 10;

	[Header("是否自动滚动"), SerializeField] bool isAutoScroll;
	[Header("自动滚动停顿时间"), SerializeField] float autoScrollStayTime = 2f;

	float radius;       // 计算后的实际布局半径
	int index;          // 当前选中页面的索引
	float gapAngle;     // 每个子页面之间的角度间隔
	List<Transform> sortedChildren;         // 按名称排序后的子对象列表
	List<Transform> depthSortedChildren;    // 按深度排序的子对象列表（用于层级管理）
	int contentCount;           // 子页面总数
	float screenWidthCache;     // 屏幕宽度缓存（用于优化计算）
	Dictionary<Transform, CanvasGroup> canvasGroupCache = new Dictionary<Transform, CanvasGroup>(); // 缓存CanvasGroup组件

	/// <summary>
	/// 当前方向角度计算属性（-360度标准化）
	/// </summary>
	float CurrentAngle => (Vector3.SignedAngle(rotationPivot.forward, Vector3.forward, Vector3.up) - 360) % 360;

	void Start()
	{
		if (content == null || rotationPivot == null)
			HKDebug.LogError("Content 或 RotationPivot 为空引用，未设置！");

		InitializeContent(); // 初始化内容
	}

	void Update()
	{
#if UNITY_EDITOR
		if (content == null || rotationPivot == null)
			HKDebug.LogError("Content 或 RotationPivot 为空引用，未设置！");

		// 编辑器模式下实时更新布局
		if (!Application.isPlaying)
			InitializeContent();
#endif

		if (isAutoScroll)
		{
			// 每隔 autoScrollTime 的时间，自动滚动到下一页 MoveIndex(1)
			if (Time.time % autoScrollStayTime < Time.deltaTime)
			{
				MoveIndex(1);
			}
		}

		// 没有子对象时跳过更新
		if (contentCount == 0)
			return;

		UpdateRadius();             // 更新布局半径
		UpdateChildrenLayout();     // 更新子对象位置
		UpdateVisualHierarchy();    // 更新视觉层级
	}

	/// <summary>
	/// 初始化内容（获取子对象并排序）
	/// </summary>
	void InitializeContent()
	{
		contentCount = content.childCount;
		if (contentCount == 0) return;

		foreach (Transform child in content)
		{
			canvasGroupCache[child] = child.GetComponent<CanvasGroup>();
		}

		InitializeContentLists();
		gapAngle = 360f / contentCount;
		UpdateRadius(true);
	}

	/// <summary>
	/// 初始化子对象列表并进行名称排序
	/// </summary>
	void InitializeContentLists()
	{
		sortedChildren = new List<Transform>(contentCount);
		depthSortedChildren = new List<Transform>(contentCount);

		for (int i = 0; i < contentCount; i++)
		{
			var child = content.GetChild(i);
			sortedChildren.Add(child);
			depthSortedChildren.Add(child);
		}
		sortedChildren.Sort((a, b) => a.name.CompareTo(b.name));
	}

	/// <summary>
	/// 更新布局半径（根据屏幕尺寸动态计算）
	/// </summary>
	void UpdateRadius(bool forceUpdate = false)
	{
		if (forceUpdate || screenWidthCache != Screen.width)
		{
			screenWidthCache = Screen.width;
			var rectTransform = sortedChildren[0] as RectTransform;
			radius = radiusMult * screenWidthCache / rectTransform.sizeDelta.x;
		}
	}

	/// <summary>
	/// 更新子对象布局位置（圆形分布）
	/// </summary>
	void UpdateChildrenLayout()
	{
		var currentAngle = CurrentAngle;

		// HKDebug.Log(CurrentAngle.ToString());

		for (int i = 0; i < contentCount; i++)
		{
			float theta = gapAngle * i - (90f - currentAngle);
			float radians = theta * Mathf.Deg2Rad;
			var targetPos = content.localPosition + new Vector3(Mathf.Cos(radians), 0, Mathf.Sin(radians)) * radius;
			sortedChildren[i].localPosition = Vector3.Lerp(sortedChildren[i].localPosition, targetPos, Time.deltaTime * 25);
		}
	}

	/// <summary>
	/// 更新视觉层级（深度排序、缩放、透明度）
	/// </summary>
	void UpdateVisualHierarchy()
	{
		depthSortedChildren.Sort((a, b) => -a.localPosition.z.CompareTo(b.localPosition.z));

		for (int i = 0; i < contentCount; i++)
		{
			var child = depthSortedChildren[i];
			child.SetSiblingIndex(i);

			float normalizedDepth = Mathf.Abs(child.localPosition.z - radius) / (radius * 2);
			float scaleFactor = Mathf.Lerp(minScale, 1f, normalizedDepth);
			child.localScale = Vector3.one * scaleFactor;

			var canvasGroup = canvasGroupCache[child];
			if (canvasGroup)
			{
				// canvasGroup.alpha = Mathf.Pow(scaleFactor, alphaExponent);
				canvasGroup.DOFade(Mathf.Pow(scaleFactor, alphaExponent), 0.5f).SetEase(Ease.Linear);
			}
		}
	}

	/// <summary>
	/// 移动当前索引（切换页面）
	/// </summary>
	/// <param name="offset">偏移量（通常为±1）</param>
	void MoveIndex(int offset)
	{
		index = (index + offset + contentCount) % contentCount;
		rotationPivot.DORotateQuaternion(Quaternion.Euler(0, index * gapAngle, 0), 0.8f);
	}

	/// <summary>
	/// 切换至上一页
	/// </summary>
	public void SwitchToLastPage()
	{
		MoveIndex(-1);
	}

	/// <summary>
	/// 切换至下一页
	/// </summary>
	public void SwitchToNextPage()
	{
		MoveIndex(1);
	}
}